package com.jackstraw.jack_base.datasource.redis.config;

import com.jackstraw.jack_base.datasource.common.config.DataSourceConfiguration;
import com.jackstraw.jack_base.datasource.common.entity.Properties;
import com.jackstraw.jack_base.datasource.redis.bean.CacheManagerMap;
import com.jackstraw.jack_base.datasource.redis.bean.MyLettuceClientConfigurationBuilderCustomizer;
import com.jackstraw.jack_base.datasource.redis.bean.RedisDataSourceTemplate;
import com.jackstraw.jack_base.datasource.redis.bean.RedisProperties;
import com.jackstraw.jack_base.datasource.redis.bean.RedisPropertiesEntity;
import com.jackstraw.jack_base.datasource.redis.bean.RedisRouting;
import com.jackstraw.jack_base.datasource.redis.bean.RedisTemplateCut;
import com.jackstraw.jack_base.datasource.redis.exception.BadRedisException;
import com.jackstraw.jack_base.datasource.redis.factory.impl.RedisBuildFactory;
import com.jackstraw.jack_base.datasource.redis.util.RedisUtil;
import com.jackstraw.jack_base.util.ObjectUtil;
import com.jackstraw.jack_base.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;


/**
 * redis配置类
 */
@Slf4j
@Configuration
@EnableCaching
@EnableAutoConfiguration(exclude = {RedisAutoConfiguration.class, RedissonAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class})
public class RedisConfiguration extends DataSourceConfiguration<RedisRouting,
        RedisPropertiesEntity,
        RedisDataSourceTemplate,
        RedisBuildFactory,
        RedisTemplateCut,
        RedisProperties,
        RedisConfiguration> {

    public RedisConfiguration(ApplicationContext applicationContext, Environment environment) {
        super(applicationContext, environment);
    }

    @Bean
    @Primary
    @ConditionalOnMissingBean(LettuceClientConfigurationBuilderCustomizer.class)
    public LettuceClientConfigurationBuilderCustomizer lettuceClientConfigurationBuilderCustomizer() {
        return new MyLettuceClientConfigurationBuilderCustomizer();
    }

    @Override
    @Bean("redisProperties")
    @ConfigurationProperties(prefix = "jack.datasource.redis")
    public RedisProperties properties() {
        return new RedisProperties();
    }

    @Override
    @Bean("redisBuildFactory")
    public RedisBuildFactory dataSourceBuildFactory() {
        return new RedisBuildFactory();
    }

    @Override
    @Bean("redisTemplateCut")
    @ConditionalOnBean(name = {"redisBuildFactory"})
    public RedisTemplateCut dataSourceTemplateCut(RedisBuildFactory dataSourceBuildFactory) {
        return new RedisTemplateCut(dataSourceBuildFactory);
    }

    @Bean
    @ConditionalOnMissingBean(value = CacheProperties.class)
    @ConfigurationProperties(prefix = "jack.datasource.cache")
    public CacheProperties cacheProperties() {
        return new CacheProperties();
    }


    @Override
    @Bean("redisRouting")
    @ConditionalOnBean(name = {"lettuceClientConfigurationBuilderCustomizer", "redisProperties", "redisTemplateCut", "cacheProperties"})
    public RedisRouting routing() {
        RedisProperties properties = SpringUtil.getBean("redisProperties", RedisProperties.class);
        if (ObjectUtil.ObjectUtilByLang3.isEmpty(properties)) {
            log.error("Redis配置文件异常");
            throw new BadRedisException("00001", "Redis配置文件异常");
        }

        RedisTemplateCut redisTemplateCut = SpringUtil.getBean("redisTemplateCut", RedisTemplateCut.class);
        if (ObjectUtil.ObjectUtilByLang3.isEmpty(redisTemplateCut)) {
            log.error("Redis切面异常");
            throw new BadRedisException("00002", "Redis切面异常");
        }

        RedisRouting redisRouting = new RedisRouting();
        redisRouting.routing(properties, redisTemplateCut);
        return redisRouting;
    }


    @Primary
    @Bean("cacheManager")
    @ConditionalOnBean(name = {"redisRouting"})
    public CacheManager cacheManager(RedisRouting routing) {
        return new CacheManagerMap(routing);
    }


    @Bean("redisUtil")
    @ConditionalOnBean(name = {"redisRouting"})
    public RedisUtil redisUtil(RedisRouting routing) {
        return RedisUtil.build(routing);
    }
}
